home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / ODF Release 3 / ODFDev / Form / Sources / Frame.cpp < prev    next >
Encoding:
Text File  |  1996-12-16  |  19.1 KB  |  624 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                Frame.cpp
  4. //    Release Version:    $ ODF 3 $
  5. //
  6. //    Copyright:            (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "Form.hpp"
  11.  
  12. #ifndef FRAME_H
  13. #include "Frame.h"
  14. #endif
  15.  
  16. #ifndef CONTENT_H
  17. #include "Content.h"
  18. #endif
  19.  
  20. #ifndef DIALOG_H
  21. #include "Dialog.h"
  22. #endif
  23.  
  24. #ifndef PART_H
  25. #include "Part.h"
  26. #endif
  27.  
  28. #ifndef VIEW_H
  29. #include "View.h"
  30. #endif
  31.  
  32. #ifndef EDITCMD_H
  33. #include "EditCmd.h"
  34. #endif
  35.  
  36. // ----- Framework Layer -----
  37.  
  38. #ifndef FWBUTTON_H
  39. #include "FWButton.h"
  40. #endif
  41.  
  42. #ifndef FWTABBER_H
  43. #include "FWTabber.h"
  44. #endif
  45.  
  46. #ifndef FWIDLE_H
  47. #include "FWIdle.h"
  48. #endif
  49.  
  50. #ifndef FWUTIL_H
  51. #include "FWUtil.h"
  52. #endif
  53.  
  54. #ifndef FWSCROLR_H
  55. #include "FWScrolr.h"
  56. #endif
  57.  
  58. #ifndef FWSCLBAR_H
  59. #include "FWSclBar.h"
  60. #endif
  61.  
  62. #ifndef FWGROWBX_H
  63. #include "FWGrowBx.h"
  64. #endif
  65.  
  66. #ifndef FWBUTTON_H
  67. #include "FWButton.h"
  68. #endif
  69.  
  70. #ifndef FWPOPUP_H
  71. #include "FWPopup.h"
  72. #endif
  73.  
  74. #ifndef FWCONTXT_H
  75. #include "FWContxt.h"
  76. #endif
  77.  
  78. #ifndef FWPRHDLR_H
  79. #include "FWPrHdlr.h"
  80. #endif
  81.  
  82. // ----- OS Layer -----
  83.  
  84. #ifndef FWMENU_H
  85. #include "FWMenu.h"
  86. #endif
  87.  
  88. #ifndef FWEVENT_H
  89. #include "FWEvent.h"
  90. #endif
  91.  
  92. #ifndef FWALERT_H
  93. #include "FWAlert.h"
  94. #endif
  95.  
  96. #ifndef SLMixOS_H
  97. #include "SLMixOS.h"
  98. #endif
  99.  
  100. #ifndef FWCFMRES_H
  101. #include "FWCFMRes.h"
  102. #endif
  103.  
  104. #ifndef FWODMISC_H
  105. #include "FWODMisc.h"
  106. #endif
  107.  
  108. #ifndef FWRESOUR_H
  109. #include "FWResour.h"
  110. #endif
  111.  
  112. // ----- Graphic Includes -----
  113.  
  114. #ifndef FWRECT_H
  115. #include "FWRect.h"
  116. #endif
  117.  
  118. #ifndef FWTXTBOX_H
  119. #include "FWTxtBox.h"
  120. #endif
  121.  
  122. #ifndef FWRECSHP_H
  123. #include "FWRecShp.h"
  124. #endif
  125.  
  126. #ifndef FWPICSHP_H
  127. #include "FWPicShp.h"        
  128. #endif
  129.  
  130. #ifndef FWRGNSHP_H
  131. #include "FWRgnShp.h"        
  132. #endif
  133.  
  134. #ifndef FWLINSHP_H
  135. #include "FWLinShp.h"        
  136. #endif
  137.  
  138. // ----- Foundation Layer -----
  139.  
  140. #ifndef FWNOTIFN_H
  141. #include "FWNotifn.h"
  142. #endif
  143.  
  144. #ifndef FWNOTDEF_H
  145. #include "FWNotDef.h"
  146. #endif
  147.  
  148. // ----- PPob View Support -----
  149.  
  150. #if FW_PPOB_VIEWS
  151. #include "FWPPobRd.h"
  152. #endif
  153.  
  154. //========================================================================================
  155. // Runtime Informations
  156. //========================================================================================
  157.  
  158. #ifdef FW_BUILD_MAC
  159. #pragma segment odfform
  160. #endif
  161.  
  162. FW_DEFINE_AUTO(CFormFrame)
  163. FW_DEFINE_CLASS_M2(CFormFrame, FW_CFrame, FW_MReceiver)
  164.  
  165. //========================================================================================
  166. // CFormFrame class
  167. //========================================================================================
  168.  
  169. //----------------------------------------------------------------------------------------
  170. // CFormFrame::CFormFrame
  171. //----------------------------------------------------------------------------------------
  172. CFormFrame::CFormFrame(Environment* ev, ODFrame* odFrame, FW_CPresentation* presentation, CFormPart* part)
  173.     : FW_CFrame(ev, odFrame, presentation, part),
  174.     fFormPart(part),
  175.     fIdler(NULL),
  176.     fViewTabber(NULL)
  177. {
  178.     // We must create an idler to see the caret blink in the text-edit views
  179.     fIdler = FW_NEW(FW_CIdler, (this, 15));
  180.     fIdler->RegisterIdle(ev);                
  181. }
  182.  
  183. //----------------------------------------------------------------------------------------
  184. // CFormFrame::~CFormFrame
  185. //----------------------------------------------------------------------------------------
  186.  
  187. CFormFrame::~CFormFrame()
  188. {
  189.     delete fIdler;
  190.     
  191.     // fViewTabber is deleted automatically because it's an attached event handler
  192. }
  193.  
  194. //----------------------------------------------------------------------------------------
  195. //    CFormFrame::PostCreateViewFromStream
  196. //----------------------------------------------------------------------------------------
  197. // PostCreateViewFromStream is called after subviews are created from resources.  
  198. // Implement initializations for this view that can't be done from a stream.
  199.  
  200. void CFormFrame::PostCreateViewFromStream(Environment* ev)
  201. {
  202.     // ----- Add a ViewTabber to the frame 
  203. #if FW_ODFRC_VIEWS
  204.     fViewTabber = new FW_CViewTabber(ev, this); 
  205. #endif
  206.  
  207. #if FW_ODFRC_VIEWS
  208.     // Fix the centering of the title (FW_LStaticText doesn't include an options field).
  209.     FW_CStaticText* st = FW_DYNAMIC_CAST (FW_CStaticText, FindViewByID (ev, 'titl'));
  210.     if (st != kODNULL) {
  211.         FW_CTextBoxShape* tbs = st->GetTextBoxShape (ev);
  212.         tbs->SetOptions (FW_kTextBoxJustifyHCenter);
  213.     }
  214. #endif
  215.     
  216.     // ----- Additional processing for non-root (i.e. embedded) frames
  217.     if (IsRoot(ev) == false) 
  218.     {
  219.         // Remove the GrowBox (delete is enough to remove it from the subviews list)
  220. //        FW_CView* growBox = FindViewByID(ev, kGrowBoxID);
  221. //        delete growBox;
  222.         
  223.         // Shrink the scroll-bars to leave space for a 1 pixel border
  224.         // NOTE: It's against OpenDoc HI guidelines to keep scroll-bars in embedded frames
  225.         //         and also to have an embedded frame draw its own border! 
  226.         //         Drawing the border should be the responsability of the container.
  227.         //         ... We wanted this sample to be different.
  228.         
  229.         FW_CView* hSB = FindViewByID(ev, kHorzScrollBarID);
  230.         if (hSB)
  231.         {
  232.             FW_CPoint hSBLoc = hSB->GetLocation(ev);
  233.             hSBLoc.x += FW_kFixedPos1;
  234.             hSBLoc.y -= FW_kFixedPos1;
  235.             FW_CPoint hSBSize = hSB->GetSize(ev);
  236.             hSBSize.x -= FW_IntToFixed(2);
  237.             hSB->SetLocation(ev, hSBLoc, FW_kDontRedraw);
  238.             hSB->SetSize(ev, hSBSize, FW_kDontRedraw);
  239.         }
  240.         
  241.         FW_CView* vSB = FindViewByID(ev, kVertScrollBarID);
  242.         if (vSB)
  243.         {
  244.             FW_CPoint vSBLoc = vSB->GetLocation(ev);
  245.             vSBLoc.x -= FW_kFixedPos1;
  246.             vSBLoc.y += FW_kFixedPos1;
  247.             FW_CPoint vSBSize = vSB->GetSize(ev);
  248.             vSBSize.y -= FW_IntToFixed(2);
  249.             vSB->SetLocation(ev, vSBLoc, FW_kDontRedraw);
  250.             vSB->SetSize(ev, vSBSize, FW_kDontRedraw);
  251.         }
  252.     }
  253.         // now that views have been created, tell the content
  254.         // object to register interests
  255.     CFormContent* content = (CFormContent*)GetFormPart()->GetContent(ev);
  256.     content->AddViewInterests(ev, this);
  257.     content->ExportToViews(ev, this);
  258. }
  259.  
  260. //----------------------------------------------------------------------------------------
  261. // CFormFrame::CreateSubViews
  262. //----------------------------------------------------------------------------------------
  263. // The subviews created for this frame are:
  264. //
  265. //   CFormFrame 
  266. //         |_____ grow box      (only for root frame)
  267. //         |
  268. //         |_____ horzSB         (horizontal scrollbar)
  269. //         |_____ vertSB         (vertical scrollbar)
  270. //         |
  271. //         |_____ contentView     (scrolling form)
  272. //                      |
  273. //                    |_____ <Several Controls, Edit views and 1 list box>...
  274. //                                      
  275. // This sample shows how to create views in 3 different methods
  276. // 1) Using the ODF resource format in Views.fr --> flag FW_ODFRC_VIEWS
  277. // 2) Using a PPob resource in ODFForm.ppob --> flag FW_PPOB_VIEWS
  278. // 3) Or doing it by hand if you prefer! (NOT recommended)
  279. // Note: the FW_ODFRC_VIEWS flag results in this method not being called at all;
  280. // it's handled in the framework.
  281.  
  282. void CFormFrame::CreateSubViews(Environment* ev)
  283. {
  284.     FW_Boolean isPrinting = fFormPart->GetPrintPresentation() == GetPresentation(ev);
  285.     const short viewID = isPrinting ? kPrintFormView : IsRoot(ev) ? kRootFormView : kEmbeddedFormView;
  286.     
  287. #if FW_PPOB_VIEWS
  288.     // Load views from PPob resource.  
  289.     // - Pass NULL as receiver arg (2nd "this") if you don't want to link controls automatically
  290.     FW_CPPobReader::CreateViews (ev, viewID, this, this);
  291. #endif
  292.  
  293. #if 0
  294.     //
  295.     // This code is OUT OF DATE! It won't work well, if it works at all
  296.     // It is still here so you can look at it in case you need to manually create
  297.     // one or two views, but this approach is not recommended in general. Use a
  298.     // view editor (MetroWerks Constructor and the PPob support), or ODFRC .fr files.
  299.     //
  300.     // This code is compiled if you didn't define any of the 2 FW_XXX_VIEWS flags
  301.     // above, i.e. it shows how to create views by program instead of using resources
  302.     // See also CFormView::CreateSubViews().
  303.     
  304.     FW_CRect frameRect = GetBounds(ev);  
  305.     FW_CRect contentRect;    // frame rect without scroll-bars
  306.     GetContentRect(ev, contentRect);
  307.     
  308.     if (IsRoot(ev)) 
  309.     {
  310.         // ----- Create the GrowBox only in root frame
  311.         FW_CGrowBox* growBox = new FW_CGrowBox(ev, this, 0, contentRect.BotRight());
  312.     }
  313.     else
  314.     {
  315.         // ----- Leave space to draw 1 pixel border in non-root frames
  316.         frameRect.Inset(FW_kFixedPos1);
  317.     }
  318.  
  319.     // ----- Create the vertical & horizontal scroll bars inside the frame
  320.     FW_CRect vertSbRect(contentRect.right, frameRect.top - FW_kFixedPos1, 
  321.                     frameRect.right + FW_kFixedPos1, contentRect.bottom + FW_kFixedPos1);
  322.     FW_CScrollBar* vertSB = FW_NEW(FW_CScrollBar, (ev, this, 0, vertSbRect));
  323.     
  324.     FW_CRect horzSbRect(frameRect.left - FW_kFixedPos1, contentRect.bottom, 
  325.                     contentRect.right + FW_kFixedPos1, frameRect.bottom + FW_kFixedPos1);
  326.     FW_CScrollBar* horzSB = FW_NEW(FW_CScrollBar, (ev, this, 0,horzSbRect));        
  327.  
  328.     // ----- Create the content view with the extent of the picture
  329.     //         (The content view's subviews are created later in CFormView::CreateSubViews)
  330.     FW_CRect    pictRect;
  331.     CFormView* contentView = new CFormView(ev, this, contentRect, kFormPict1, kFormPict2);
  332.     contentView->BecomeContentView(ev); 
  333.     
  334.     // ----- Create a scroller  (this must be done AFTER the content view)
  335.     FW_CScroller* scroller = FW_NEW(FW_CScrollBarScroller, (ev, this, horzSB, vertSB));
  336.     AdoptScroller(ev, scroller);
  337.     
  338.     // ----- Add a ViewTabber to the frame 
  339.     fViewTabber = new FW_CViewTabber(ev, this); 
  340. #endif
  341. }
  342.  
  343. //----------------------------------------------------------------------------------------
  344. // CFormFrame::GetContentRect
  345. //----------------------------------------------------------------------------------------
  346.  
  347. void CFormFrame::GetContentRect(Environment* ev, FW_CRect& rect)
  348. {
  349.     rect = GetBounds(ev);
  350.     
  351.     // Leave space to draw 1 pixel border in non-root frames
  352.     if (IsRoot(ev) == FALSE)
  353.         rect.Inset(FW_kFixedPos1);
  354.         
  355.     FW_CPoint sbSize = FW_CScrollBar::GetDefaultScrollBarSize();
  356.  
  357.     rect.right -= sbSize.x;
  358.     rect.bottom -= sbSize.y;
  359. }
  360.  
  361. //----------------------------------------------------------------------------------------
  362. // CFormFrame::Draw
  363. //----------------------------------------------------------------------------------------
  364.  
  365. void CFormFrame::Draw(Environment *ev, ODFacet* odFacet, ODShape* invalidShape)
  366. {
  367.     // Draw a gray background.
  368.     // We do a complicated mess of stuff to try to avoid drawing over any subviews.
  369.     
  370.     FW_CRect contentRect;
  371.     GetContentRect(ev, contentRect);
  372.     
  373.     // Get the content view's bounds in our coordinate system
  374.     FW_CView* cview = GetFrame(ev)->GetContentView(ev);
  375.     FW_CRect formRect (cview->GetBounds(ev));
  376.     cview->GetSuperView(ev)->ViewToFrame (ev, formRect);
  377.     
  378.     // Don't draw this stuff when printing
  379.     Boolean isntPrinting = odFacet->GetCanvas(ev)->IsDynamic(ev);
  380.     
  381.     FW_CViewContext vc(ev, this, odFacet, invalidShape);
  382.     
  383.     // Draw a gray background around the content view if it's smaller
  384.     if (formRect.right < contentRect.right || formRect.bottom < contentRect.bottom ) {
  385.  
  386.         // Draw outside the center view to avoid flashing 
  387.         FW_CAcquiredODShape aqPaneShape = ::FW_NewODShape(ev, contentRect);
  388.         FW_CAcquiredODShape aqCenterShape = ::FW_NewODShape(ev, formRect);
  389.         aqPaneShape->Subtract(ev, aqCenterShape);
  390.     
  391.         FW_CRegionShape::RenderRegion(vc, aqPaneShape, FW_kFill, FW_kRGBLightGray);
  392.     
  393.         // Draw a shadow frame around the content view
  394.         if (isntPrinting) {
  395.             formRect.Inset(-FW_kFixedPos1,-FW_kFixedPos1);
  396.              FW_CRectShape::RenderRect(vc, formRect, FW_kFrame);
  397.              FW_CPoint p1(formRect.left, formRect.bottom);
  398.              FW_CPoint p2(formRect.right, formRect.bottom);
  399.              FW_CPoint p3(formRect.right, formRect.top);
  400.              if (formRect.bottom < contentRect.bottom - FW_kFixedPos1)
  401.                  FW_CLineShape::RenderLine(vc, p1, p2);
  402.             if (formRect.right < contentRect.right - FW_kFixedPos1)
  403.                  FW_CLineShape::RenderLine(vc, p2, p3);
  404.         }
  405.     }
  406.     
  407.     if (IsRoot(ev) == FALSE)
  408.     {
  409.         // Draw a 1 pixel border in non-root frames
  410.         FW_CRect frameRect = GetBounds(ev);        
  411.          FW_CRectShape::RenderRect(vc, frameRect, FW_kFrame);
  412.     }
  413. }
  414.  
  415. //----------------------------------------------------------------------------------------
  416. //    CFormFrame::FrameShapeChanged
  417. //----------------------------------------------------------------------------------------
  418.  
  419. void CFormFrame::FrameShapeChanged(Environment *ev)
  420. {
  421.     // By default a FW_CFrame view is not refreshed entirely when resized.
  422.     // You must decide if your content's appearance depends on the frame's size.
  423.     // If it doesn't you don't need to override FrameShapeChanged().
  424.     // Here it's a little bit tricky because the formView is centered inside the frame,
  425.     // so the only case where the content is fixed is when the frame is smaller than the
  426.     // formView, i.e. the formView is anchored to the topleft corner.
  427.  
  428.     // Check if the formView was anchored before resizing
  429.     FW_CRect contentRect;
  430.     GetContentRect(ev, contentRect);
  431.     FW_CSuperView* formView = GetFrame(ev)->GetContentView(ev);
  432.     FW_CPoint formTopLeft(formView->GetBounds(ev).TopLeft());
  433.     FW_Boolean    anchoredBefore = (contentRect.TopLeft() == formTopLeft) ? TRUE : FALSE;    
  434.  
  435.     // Resize the frame (this invalidates only the modified region)
  436.     FW_CFrame::FrameShapeChanged(ev);    
  437.     
  438.     // Check if the formView is anchored after resizing
  439.     GetContentRect(ev, contentRect);
  440.     formTopLeft = formView->GetBounds(ev).TopLeft();
  441.     FW_Boolean    anchoredAfter = (contentRect.TopLeft() == formTopLeft) ? TRUE : FALSE;    
  442.     
  443.     // Invalidate the whole frame if we need redraw outside the formview
  444.     if (!anchoredBefore || !anchoredAfter)
  445.         Invalidate(ev);
  446. }
  447.  
  448. //----------------------------------------------------------------------------------------
  449. //    CFormFrame::HandleNotification
  450. //----------------------------------------------------------------------------------------
  451.  
  452. void CFormFrame::HandleNotification(Environment* ev, const FW_CNotification& notification)
  453. {
  454.     // Handle notification messages for the registered controls.
  455.     // GetMessage() allows to switch on the type of notification.  For each message
  456.     // we can down-cast "notification" directly to the right subclass, without
  457.     // having to use RTTI, because the message is unique to that type.
  458.     
  459.     switch (notification.GetMessage()) 
  460.     {
  461.         case FW_kButtonPressedMsg: 
  462.         {
  463.             const FW_CControlNotification& controlNotification = 
  464.                                                     (FW_CControlNotification&) notification;
  465.  
  466.             // This frame has several active buttons, we must switch on the button id
  467.             ODID viewID = controlNotification.GetViewID(ev);
  468.             switch (viewID) 
  469.             {
  470.                 case kNoRadioID:
  471.                     // Show alert if "No" is being selected... and select "Yes" again :)
  472.                     if (controlNotification.GetControl(ev)->GetValue(ev) == 1)
  473.                     {
  474.                         // FW_Beep();
  475.                         FW_NoteAlert(FW_CString(), FW_CString(" We don't believe you! "));
  476.                         FW_CButton* yesButton = (FW_CButton*)FindViewByID(ev, kYesRadioID);
  477.                         yesButton->SetValue(ev, 1);
  478.                     }
  479.                     break;
  480.                     
  481.                 case kSubscribeButtonID:
  482.                     // Open modal dialog to pick a password
  483.                     OpenPasswordDialog(ev);
  484.                     break;
  485.                     
  486.                 case kAddButtonID:
  487.                 case kRemoveButtonID:
  488.                     // Add/Remove an item in the list box
  489.                     ModifyPlatformList(ev, viewID == kAddButtonID ? TRUE : FALSE);
  490.                     break;
  491.             }
  492.         } 
  493.         break;
  494.         
  495.         case FW_kListBoxDoubleClickedMsg:
  496.         {
  497.             const FW_CListBoxNotification& listBoxNotification = 
  498.                                                     (FW_CListBoxNotification&) notification;
  499.             
  500.             // Beep if we double-click on the first item
  501.             if (listBoxNotification.GetListBox(ev)->GetSelectedItem(ev) == 1)
  502.                 FW_Beep();
  503.         }
  504.         break;
  505.         
  506.         default:
  507.             FW_ASSERT("CFormFrame can't respond to this");
  508.             break;
  509.     }
  510. }
  511.  
  512. //----------------------------------------------------------------------------------------
  513. //    CFormFrame::OpenPasswordDialog
  514. //----------------------------------------------------------------------------------------
  515.  
  516. void CFormFrame::OpenPasswordDialog(Environment* ev)
  517. {
  518.     // position is not important here because we use FW_kStandardDialogPosition in the
  519.     // window style to center the dialog properly.
  520.     FW_CPoint    position(FW_kZeroPoint);
  521.     FW_CPoint    size(FW_IntToFixed(300), FW_IntToFixed(160));
  522.     
  523.     FW_WindowStyle style = FW_kStandardDialogPosition | FW_kHasCaption;
  524.  
  525.     FW_CPresentation* dialogPresentation = GetFormPart()->GetPwdDialogPresentation();
  526.     
  527.     // ----- Create new dialog window with the "Password" presentation -----
  528.     //
  529.     // Note: unlike the standard Mac Toolbox "ModalDialog" FW_CDialogFrame::NewModalDialog
  530.     //        returns right after creating the dialog.  Events are processed the same
  531.     //        way as any other OpenDoc frames, except that the modal focus is set.
  532.     //        (NewModalDialog can return NULL if the dialog creation failed because the 
  533.     //        modal focus could not be granted)
  534.     //
  535.     //        Here we use NewModalDialog() instead of NewAndShowModalDialog() because
  536.     //        we need to initialize a few things before opening the dialog
  537.         
  538.     CPwdDialogFrame* dialog = (CPwdDialogFrame*) FW_CDialogFrame::NewModalDialog(ev, 
  539.                             GetPart(ev),                // Your part
  540.                             dialogPresentation,         // Used in CFormPart::NewFrame
  541.                             size,                         // Window size
  542.                             position,                     // Window position
  543.                             style,                        // Make dialog moveable
  544.                             FW_CString("Password"));    // Title for moveable dialog
  545.     
  546.     if (dialog != NULL)
  547.     {                        
  548.         dialog->Initialize(ev, this);        
  549.         dialog->GetWindow(ev)->Show(ev);
  550.     }
  551. }
  552. //----------------------------------------------------------------------------------------
  553. //    CFormFrame::ModifyPlatformList
  554. //----------------------------------------------------------------------------------------
  555.  
  556. void CFormFrame::ModifyPlatformList(Environment* ev, FW_Boolean addItem)
  557. {
  558.     FW_CListBox* list = (FW_CListBox*)FindViewByID(ev, kPlatformListBoxID);
  559.     FW_ASSERT(list);
  560.     
  561.     if (addItem)
  562.     {
  563.         // Add a row after the last selected item or at the end.
  564.         short addIndex = 0;
  565.         short count = list->GetSelectionCount(ev);
  566.  
  567.         if (count > 0)
  568.         {
  569.             // We must retrieve the list of selected items in a dynamic array
  570.             short* const indexArray = new short[count];
  571.             
  572.             short read = list->GetSelectedItems(ev, count, indexArray);
  573.             FW_ASSERT(read == count);
  574.             
  575.             addIndex = indexArray[count - 1] + 1;
  576.             
  577.             delete indexArray;
  578.         }
  579.         
  580.         list->AddStringItem(ev, FW_CString("Macintosh"), addIndex);        
  581.         list->ScrollIntoView(ev, addIndex);
  582.     }
  583.     else 
  584.     {
  585.         // Remove the first selected item
  586.         short selectedItem = list->GetSelectedItem(ev);
  587.         if (selectedItem > 0)
  588.             list->DeleteItems(ev, selectedItem);
  589.  
  590.         // Update button's state
  591.         FW_CButton* rmButton = (FW_CButton*)FindViewByID(ev, kRemoveButtonID);
  592.         if (list->GetSelectedItem(ev) == 0)
  593.             rmButton->Disable(ev);
  594.     }
  595. }
  596.  
  597.  
  598. //----------------------------------------------------------------------------------------
  599. //    CFormFrame::NewPrintHandler
  600. //----------------------------------------------------------------------------------------
  601. // NewPrintHandler is all you need to support printing!
  602. // (You can also add a progress dialog resource as in ODF Draw's FWPrint.r but it's
  603. //  not necessary and not very useful with background printing)
  604.  
  605. FW_CPrintHandler* CFormFrame::NewPrintHandler(Environment* ev)
  606. {
  607. FW_UNUSED(ev);
  608.     // We use the base PrintHandler class for basic printing of the content view
  609.     // (See ODF Draw for a more advanced example)
  610.     return new FW_CPrintHandler(this, fFormPart->GetPrintPresentation());
  611. }
  612.  
  613.  
  614. //----------------------------------------------------------------------------------------
  615. //    CFormFrame::NewClipboardCommand
  616. //----------------------------------------------------------------------------------------
  617.  
  618. FW_CClipboardCommand* CFormFrame::NewClipboardCommand(Environment* ev, ODCommandID commandID)
  619. {
  620.     CEditViewCommand* cmd = FW_NEW(CEditViewCommand, (ev, commandID, this, FW_kCanUndo));
  621.     return cmd;
  622. }
  623.  
  624.